Using Transactions
When you are writing
managed objects, just as with T-SQL, it’s important to be aware of the
current transaction context under which your code may be running.
Managed database objects have the option of making use of the classes in the new System.Transactions namespace to control transactions. Following are the main objects you use to do this:
Transaction.Current— This is a static object of type Transaction that represents the current transaction. You use this object to explicitly roll back the current transaction (using Rollback()). It contains an IsolationLevel property that indicates the current transaction isolation level, as well as a TransactionCompleted event that your objects may subscribe to and a TransactionInformation property that indicates TransactionStatus
and other attributes of the transaction. You can also use this object
to manually enlist additional objects in the current transaction.
TransactionScope—
This object represents a transactional scope that is used to wrap
managed code. Note that transactions automatically roll back unless they
are explicitly committed using this object’s Complete()
method. It is enough to merely instantiate this object at the beginning
of the managed code: If a current transaction is active, the
instantiated object assumes that transaction; if not, a new transaction
is initiated.
Note that it is not
necessary to explicitly declare or even use transactions: if your
managed code is already running in the scope of a transaction, it
automatically participates in that transaction. (To turn off this
behavior, you append "enlist=false" to
your connection string.) In fact, even if your code opens additional
connections on additional servers, the transaction context is not only
preserved but is automatically promoted to a distributed transaction
that enlists all the connections involved. (The MSDTC service must be
running for distributed transactions to work.)
One thing you cannot do with
managed transactions that you can with T-SQL is begin a new transaction
and then just leave it open.
The code example in Listing 11 illustrates the use of the System.Transactions objects in a managed stored procedure. You need to add a new managed stored procedure to the SQLCLR project and call it SPTrans. Then you need to add the using statement using System.Transactions; and replace the autogenerated method with the code from Listing 11.
Listing 11. Using Transactions in a Managed Stored Procedure
[SqlProcedure] public static void SpTrans() { TransactionScope ts = null; try { SqlContext.Pipe.Send("Proc Started"); if (Transaction.Current != null) { SqlContext.Pipe.Send("A) Current tran is not null."); SqlContext.Pipe.Send("A) About to rollback current tran..."); Transaction.Current.Rollback( new ApplicationException("I wanted to do this.")); SqlContext.Pipe.Send("A) Rollback Complete."); } else { SqlContext.Pipe.Send("A) Current tran is null."); }
ts = new System.Transactions.TransactionScope(); SqlContext.Pipe.Send("New Tran Started"); if (Transaction.Current != null) SqlContext.Pipe.Send("B) Current tran is not null."); else SqlContext.Pipe.Send("B) Current tran is null.");
if (ts != null) ts.Complete(); SqlContext.Pipe.Send("B) Complete() is Complete."); } finally { if (ts != null) ts.Dispose(); SqlContext.Pipe.Send("Proc Complete"); } }
|
To test this code, you simply run the stored procedure from a query window (or use sqlcmd.exe) inside and outside a transactional scope and watch the results. Here’s an example:
BEGIN TRAN
EXEC dbo.SpTrans
ROLLBACK TRAN
EXEC dbo.SPTrans
Using the Related System Catalogs
As with other database
objects, SQL Server provides catalog views that enable you to view
loaded managed assemblies, routines, and types. The base view for
finding these objects is sys.assemblies.
To see which assemblies have been loaded , you use the following query:
SELECT TOP 5
name,
assembly_id,
permission_set_desc as permission_set
FROM sys.assemblies
ORDER BY assembly_id desc
go
name assembly_id permission_set
----------------------------------------------------------------
SQLCLR 65719 UNSAFE_ACCESS
System.Configuration.Install 65705 UNSAFE_ACCESS
System.ServiceProcess 65704 UNSAFE_ACCESS
System.Web.RegularExpressions 65703 UNSAFE_ACCESS
System.Drawing.Design 65702 UNSAFE_ACCESS
Now that you have the assembly_id for your SQLCLR project (yours will not be the same value as shown here), you can look up its routines and classes in sys.assembly_modules:
SELECT TOP 5
name,
assembly_class as class,
assembly_method as method
FROM sys.assembly_modules am
JOIN sys.assemblies a
ON am.assembly_id = a.assembly_id
WHERE a.assembly_id = 65719
GO
name class method
-------------------------------------------------------------------
SQLCLR StoredProcedures GetSetIllustrationWebLinks
SQLCLR StoredProcedures SpTrans
SQLCLR RegexLibrary MatchAll
SQLCLR XSLT XSLTransform
SQLCLR SumPrime NULL
Notice that the class holding your UDA (SumPrime) is listed, but your UDA itself is not listed. In addition, your UDT (RegexPattern) is not listed. To see everything, you right-click SQLCLR in the Assemblies node of the Object Browser and then select View Dependencies.